package com.kepler.social.generic;

import com.kepler.social.core.config.SeqDatasourceConfiguration;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

@Service
@Slf4j
public class SeqHelper {

    @Resource
    private SeqDatasourceConfiguration seqDatasourceConfiguration;

    private HikariDataSource seqDataSource ;

    private HikariDataSource seqDataSource() throws NumberFormatException {

        if (null != seqDataSource) {
            return seqDataSource;
        }
        synchronized (this) {
            if (null != seqDataSource) {
                return seqDataSource;
            }
            seqDataSource = new HikariDataSource();
            seqDataSource.setDriverClassName(seqDatasourceConfiguration.getDriverClass());
            seqDataSource.setJdbcUrl(seqDatasourceConfiguration.getUrl());
            seqDataSource.setUsername(seqDatasourceConfiguration.getUserName());
            seqDataSource.setPassword(seqDatasourceConfiguration.getPassWord());
            seqDataSource.setMaximumPoolSize(seqDatasourceConfiguration.getMaximumPoolSize());
            seqDataSource.setConnectionTimeout(seqDatasourceConfiguration.getConnectionTimeout());
            seqDataSource.setMaxLifetime(seqDatasourceConfiguration.getMaxLifetime());
            seqDataSource.setConnectionTestQuery(seqDatasourceConfiguration.getConnectionTestQuery());
            seqDataSource.setMinimumIdle(seqDatasourceConfiguration.getMinimumIdle());
            return seqDataSource;
        }
    }

    public Long getSeqId(String bizName) {
        Connection conn;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = this.seqDataSource().getConnection();
            String sql = buildSql(bizName);
            ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.executeUpdate();
            rs = ps.getGeneratedKeys();
            rs.next();
            long id = rs.getLong(1);
            return id;
        } catch (SQLException e) {
            // 表不存在
            if (e.getErrorCode() == 1146) {
//                    // 创建表
//                    createSequence(name, conn);
                log.error("{}",e,e);
            } else {
                // db错误
                log.error("getSeqId 错误 {}",e,e);
            }
            // 失败时返回0L
            return 0L;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (ps != null) {
                    ps.close();
                }
            } catch (SQLException e) {
                // do nothing
            }
        }
    }

    private String buildSql(String name) {
        StringBuilder sb = new StringBuilder();
        sb.append("REPLACE INTO `seq_");
        sb.append(name);
        sb.append("` (stub) VALUES('a')");
        return sb.toString();
    }

    public synchronized void createSequence(String name) {
        Connection conn ;
        Statement statement = null;
        try {
            conn = this.seqDataSource().getConnection();
            statement = conn.createStatement();
            try {
                // 先判断表是否存在，防止线程阻塞造成多次建表
                statement.execute("select 1 from `seq_" + name + "`");
            } catch (SQLException e) {
                if (e.getErrorCode() == 1146) {
                    statement.execute("CREATE TABLE `seq_" + name
                            + "` (`id` BIGINT(16) NOT NULL AUTO_INCREMENT,`stub` CHAR(1) NOT NULL DEFAULT '', PRIMARY KEY (`id`), UNIQUE KEY (`stub`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8");
                    log.debug("创建表：" + name);
                }
            }
        } catch (SQLException e) {
            log.error("创建表：" + name + "失败。");
            e.printStackTrace();
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }



    @PreDestroy
    public void destory() {
        if (null != seqDataSource) {
            seqDataSource.close();
        }
    }

}
